<template>
    <el-select :placeholder="t('placeholder.select')" clearable :disabled="_disabled === true">
        <slot>
            <template v-if="!_slots.includes('default')" v-for="(item, index) in options">
                <el-option v-if="useRender(item as ThisItem, index as ThisKey)"
                    :label="useLabel(item as ThisItem, index as ThisKey)"
                    :value="useValue(item as ThisItem, index as ThisKey)"
                    :disabled="useDisabled(item as ThisItem, index as ThisKey)">
                    <slot name="option" :item="(item as ThisItem)" :index="(index as ThisKey)"></slot>
                </el-option>
            </template>
        </slot>
    </el-select>
</template>

<script setup lang="ts" generic="T">
import type { FuncType, MySelectType, OptionAttribute, ItemType, KeyType } from './MySelect';
import { computed, useSlots } from "vue";
import useI18n from "@/hooks/useI18n";

// 当前遍历类型
type ThisT = T
// 当前遍历项类型
type ThisItem = ItemType<ThisT>
// 当前遍历 key 类型
type ThisKey = KeyType<ThisT>

const t = useI18n()
const props = defineProps<MySelectType<ThisT>>()
const _slots = computed(() => Object.keys(useSlots()))
const slotsInOption = computed(() => _slots.value.includes("option"))

/**
 * @description 参数归一化
 * @param params 需要归一化的参数
 * @param val 当前遍历项
 * @param defaultVal 使用默认值
 * @returns 归一化后的函数
 */
const _formatNormail = <DT>(params: OptionAttribute<ThisT> | undefined, item: ThisItem, defaultVal: DT) => {
    // 省略 使用默认值
    if (params === undefined) {
        return () => defaultVal
    }

    // 是一个函数
    if (typeof params === "function") {
        return params
    }

    // 是数组对象中 某个 key
    const label = item[params as keyof ThisItem]
    if (label !== undefined) {
        return () => label
    }

    throw new Error("传入参数值错误")
}

/**
 * @description 获取归一化后处理数据
 * @param props 当前遍历项
 * @param item 当前遍历项
 * @param key 当前遍历 key
 * @param defaultVal 未传递 props 时使用的默认值
 * @returns 归一化函数执行结果
 */
const useFormatNormail =
    <DT, RT>(props: OptionAttribute<ThisT> | undefined, item: ThisItem, key: ThisKey, defaultVal: DT): RT => {
        const newParams = _formatNormail(props, item, defaultVal)
        return newParams(item, key)
    }

/**
 * @description 返回 label 使用数据
 * @param item 当前遍历项
 * @param key 当前遍历 key
 * @returns label 值
 */
const useLabel: FuncType<ThisT> = (item, key) => {
    if (slotsInOption.value) {
        return void 0 as any
    }

    return useFormatNormail(props.label, item, key, item)
}

/**
 * @description 返回 value 使用数据
 * @param item 当前遍历项
 * @param key 当前遍历 key
 * @returns value 值
 */
const useValue: FuncType<ThisT> = (item, key) => {
    if (slotsInOption.value) {
        return void 0 as any
    }

    return useFormatNormail(props.value, item, key, key)
}

/**
 * @description 返回 是否渲染
 * @param item 当前遍历项
 * @param key 当前遍历 key
 * @returns 是否渲染
 */
const useRender: FuncType<ThisT> = (item, key) => {
    if (slotsInOption.value) {
        return void 0 as any
    }

    return useFormatNormail(props.render, item, key, true)
}

const _disabled = computed(() => props.disabled)

/**
 * @description 返回 是否渲染
 * @param item 当前遍历项
 * @param key 当前遍历 key
 * @returns 是否渲染
 */
const useDisabled: FuncType<ThisT> = (item, key) => {
    if (typeof _disabled.value === 'boolean') {
        return props.disabled as any
    }

    return useFormatNormail(_disabled.value, item, key, false)
}

</script>

<style scoped></style>